using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Text;
using System.Web;
using AspNet.Security.OAuth.Weixin;
using Devonline.Communication.Messages;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

namespace Devonline.Identity.Admin.Controllers;

/// <summary>
/// This sample controller implements a typical login/logout/provision workflow for local and external accounts.
/// The login service encapsulates the interactions with the user data store. This data store is in-memory only and cannot be used for production!
/// The interaction service provides a way for the UI to communicate with identityserver for validation and context retrieval
/// </summary>
[SecurityHeaders]
[Description("用户账户管理")]
[Authorize(Roles = GROUP_MAINTAINERS)]
[AccessAuthorize(Code = "AS0XAccount", Name = "用户账户管理", ResourceType = ResourceType.Service, Roles = GROUP_MAINTAINERS)]
public class AccountController(
    AdminSetting appSetting,
    UserManager<User> userManager,
    SignInManager<User> signInManager,
    IdentityDbContext context,
    AuthorizationService authorizationService,
    UserStore userStore,
    IDataService<User> userService,
    ILogger<AccountController> logger,
    IAuthenticationSchemeProvider schemeProvider,
    ICaptchaService captchaService,
    IMessageCommunicator communicator,
    IOptionsMonitor<WeixinAuthenticationOptions> optionsMonitor,
    AuthenticationService authenticationService,
    PhoneNumberCaptchaService phoneNumberCaptchaService,
    WeixinIdentityService weixinIdentityService) : Controller
{
    private readonly ILogger<AccountController> _logger = logger;
    private readonly AdminSetting _appSetting = appSetting;
    private readonly UserManager<User> _userManager = userManager;
    private readonly SignInManager<User> _signInManager = signInManager;
    private readonly IdentityDbContext _context = context;
    private readonly AuthorizationService _authorizationService = authorizationService;
    private readonly UserStore _userStore = userStore;
    private readonly IDataService<User> _userService = userService;
    private readonly IAuthenticationSchemeProvider _schemeProvider = schemeProvider;
    private readonly ICaptchaService _captchaService = captchaService;
    private readonly IMessageCommunicator _communicator = communicator;
    private readonly AuthenticationService _authenticationService = authenticationService;
    private readonly PhoneNumberCaptchaService _phoneNumberCaptchaService = phoneNumberCaptchaService;
    private readonly WeixinIdentityService _weixinIdentityService = weixinIdentityService;
    private readonly WeixinAuthenticationOptions _authenticationOptions = optionsMonitor.Get(WeixinAuthenticationDefaults.AuthenticationScheme);

    #region Login
    [AllowAnonymous]
    [DisplayName("登录")]
    [HttpGet("Account/Login")]
    [AccessAuthorize(Code = "AS0XAccountLogin", ResourceType = ResourceType.Page)]
    public IActionResult Login(string returnUrl)
    {
        returnUrl ??= "/";
        //var viewModel = await BuildLoginViewModelAsync(returnUrl);
        //if (viewModel.IsExternalLoginOnly)
        //{
        //    // we only have one option for logging in and it's an external provider
        //    return RedirectToAction(nameof(ExternalController.Challenge), "External", new { scheme = viewModel.ExternalLoginScheme, returnUrl });
        //}

        return View(new LoginViewModel { ReturnUrl = returnUrl });
    }
    [AllowAnonymous]
    [DisplayName("登录")]
    [HttpPost("Account/Login")]
    [AccessAuthorize(Code = "AS0XAccountIPLogin", ResourceType = ResourceType.Page)]
    public async Task<IActionResult> LoginAsync(UserLoginModel loginModel)
    {
        _logger.LogDebug($"收到用户: {loginModel.UserName} 登录请求!");
        var (result, errorMessage) = await SignInAsync(loginModel);
        var returnUrl = loginModel.ReturnUrl ?? CHAR_SLASH.ToString();
        if (result)
        {
            _logger.LogInformation($"用户: {loginModel.UserName} 登录成功, 即将重定向到: {returnUrl}");
            return Redirect(returnUrl);
        }
        else
        {
            var viewModel = new LoginViewModel { ReturnUrl = returnUrl };
            viewModel.UserName = loginModel.UserName;
            viewModel.ErrorMessage = errorMessage;
            viewModel.Type = loginModel.Type;
            if (viewModel.IsExternalLoginOnly)
            {
                _logger.LogDebug("user {user} use the external login and will redirect to " + returnUrl, loginModel.UserName);
                return RedirectToAction(nameof(ExternalController.Challenge), "External", new { scheme = viewModel.ExternalLoginScheme, returnUrl });
            }

            _logger.LogInformation($"用户: {loginModel.UserName} 登录失败, 错误提示: {errorMessage}");
            return View(viewModel);
        }
    }
    [AllowAnonymous]
    [DisplayName("登录接口")]
    [HttpPost("api/Account/Login")]
    [AccessAuthorize(Code = "AS0XAccountILogin")]
    public async Task<IActionResult> UserLoginAsync([FromBody] UserLoginModel loginModel)
    {
        var (result, errorMessage) = await SignInAsync(loginModel, false);
        if (result)
        {
            _logger.LogInformation($"用户: {loginModel.UserName} 登录成功!");
            return Ok(new LoginResultViewModel { Type = loginModel.Type, UserName = loginModel.UserName!, Success = true, RedirectUri = loginModel.ReturnUrl });
        }
        else
        {
            _logger.LogInformation($"用户: {loginModel.UserName} 登录失败, 错误提示: {errorMessage}");
            return BadRequest(errorMessage);
        }
    }
    /// <summary>
    /// 登陆核心方法
    /// </summary>
    /// <param name="loginModel">登录的视图数据对象模型</param>
    /// <param name="isCaptchaValid">是否需要验证码</param>
    /// <returns></returns>
    private async Task<(bool, string)> SignInAsync(UserLoginModel loginModel, bool isCaptchaValid = true)
    {
        _logger.LogDebug("user {user} request to login system", loginModel.UserName);
        if (string.IsNullOrWhiteSpace(loginModel.UserName) || string.IsNullOrWhiteSpace(loginModel.Password))
        {
            _logger.LogDebug("user {user} request to login system but not provid userName and password!", loginModel.UserName);
            return (false, loginModel.Type switch
            {
                LoginType.Password => "必须输入用户名和密码!",
                LoginType.Captcha => "必须输入验证码!",
                _ => "登录方式无效!"
            });
        }

        loginModel.UserName = loginModel.UserName.ToLowerInvariant();
        if (loginModel.UserName == nameof(AuthorizeType.System) || loginModel.UserName == nameof(AuthorizeType.Anonymous))
        {
            _logger.LogDebug("user {user} access can not be allow to login system!", loginModel.UserName);
            return (false, loginModel.Type switch
            {
                LoginType.Password => "当前用户账户不可登录系统!",
                LoginType.Captcha => "当前用户账户不可登录系统!",
                _ => "登录方式无效!"
            });
        }

        if (User.Identity?.IsAuthenticated ?? false)
        {
            _logger.LogDebug("user {user} already login success", loginModel.UserName);
            return (true, string.Empty);
        }

        if (isCaptchaValid && _appSetting.CaptchaExpireTime > UNIT_ZERO)
        {
            if (string.IsNullOrWhiteSpace(loginModel.CaptchaId))
            {
                _logger.LogDebug("user {user} CAPTCHA id is empty!", loginModel.UserName);
                return (false, string.Empty);
            }

            if (string.IsNullOrWhiteSpace(loginModel.CaptchaCode))
            {
                _logger.LogDebug("user {user} CAPTCHA value is empty!", loginModel.UserName);
                return (false, "验证码不能为空!");
            }

            if (!_captchaService.Validate(loginModel.CaptchaId, loginModel.CaptchaCode))
            {
                _logger.LogDebug("user {user} CAPTCHA value is invalid!", loginModel.UserName);
                return (false, "验证码不正确!");
            }
        }

        var errorMessage = AccountOptions.ErrorMessageInvalidCredentials;
        var user = await _context.Users.FirstOrDefaultAsync(x => loginModel.Type == LoginType.Password && x.UserName == loginModel.UserName || loginModel.Type == LoginType.Captcha && x.PhoneNumberConfirmed && x.PhoneNumber == loginModel.UserName);
        if (user is null)
        {
            return (false, $"用户: {loginModel.UserName} 不存在!");
        }

        UserContext? userContext = null;
        _signInManager.AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        switch (loginModel.Type)
        {
            case LoginType.Password:
                _logger.LogDebug("user {user} request to login system for Password type", loginModel.UserName);

                if (_appSetting.SmsAuthorizeLogin is not null && _appSetting.SmsAuthorizeLogin.Enable)
                {
                    var (userNeedAuthorize, _) = await NeedLoginAuthorizeAsync(user);
                    if (userNeedAuthorize)
                    {
                        return (false, $"用户: {loginModel.UserName} 需要登录授权, 请使用短信验证码方式登录!");
                    }
                }

                var result = await _signInManager.PasswordSignInAsync(loginModel.UserName, loginModel.Password, loginModel.RememberLogin, lockoutOnFailure: true);
                if (result.Succeeded)
                {
                    userContext = await _authorizationService.GetUserContextAsync(user.UserName);
                    if (userContext is not null)
                    {
                        var userModel = await _userManager.FindByNameAsync(loginModel.UserName);
                        if (userModel is not null)
                        {
                            var claims = await userContext.User.GetUserClaimsAsync(_context, _appSetting.DataIsolate);
                            loginModel.ReturnUrl = HttpUtility.UrlDecode(_authenticationService.GetRedirectUrl(userModel, loginModel.ReturnUrl));
                            await _signInManager.SignInWithClaimsAsync(userModel, new AuthenticationProperties { IsPersistent = false, RedirectUri = loginModel.ReturnUrl }, claims);
                            _logger.LogDebug("user {user} login success for Password type", loginModel.UserName);
                            return (true, string.Empty);
                        }
                    }
                }

                if (result.IsLockedOut)
                {
                    return (false, AccountOptions.ErrorMessageLockedOut);
                }

                if (result.IsNotAllowed)
                {
                    return (false, AccountOptions.ErrorMessageNotAllowed);
                }

                break;
            case LoginType.Captcha:
                //此时, userName 和 password 分别是手机号和验证码
                _logger.LogDebug("user {user} request to login system for Captcha type", loginModel.UserName);

                var (needAuthorize, groups) = await NeedLoginAuthorizeAsync(user);
                if (_appSetting.SmsAuthorizeLogin.Enable && needAuthorize && loginModel.Password.Length < 12)
                {
                    return (false, $"用户: {loginModel.UserName} 需要登录授权, 但未正确填写短信验证码和登录授权码, 验证码格式: xxxxxx, xxxxxx");
                }

                //拆分验证码
                var passwordCaptcha = loginModel.Password;
                var authorizeCaptcha = string.Empty;
                if (_appSetting.SmsAuthorizeLogin.Enable && needAuthorize && loginModel.Password.Length >= 12)
                {
                    passwordCaptcha = loginModel.Password[..6];
                    authorizeCaptcha = loginModel.Password[^6..];
                }

                var captcha = await _phoneNumberCaptchaService.ValidateAsync(loginModel.UserName, passwordCaptcha);
                if (captcha is null)
                {
                    return (false, AccountOptions.ErrorMessageSmsCaptchaExpired);
                }

                if (!string.IsNullOrWhiteSpace(captcha.ErrorMessage))
                {
                    return (false, captcha.ErrorMessage);
                }

                //验证通过
                if (_appSetting.SmsAuthorize is not null && _appSetting.SmsAuthorizeLogin.Enable && needAuthorize)
                {
                    var authorizer = await GetLoginAuthorizeUserAsync(user, groups);
                    if (authorizer is null || string.IsNullOrWhiteSpace(authorizer.PhoneNumber))
                    {
                        return (false, "授权登录验证人配置有误, 请联系管理员处理!");
                    }

                    captcha = await _phoneNumberCaptchaService.ValidateAsync(authorizer.PhoneNumber, authorizeCaptcha, _appSetting.SmsAuthorize.TemplateCode, loginModel.UserName);
                    if (captcha is null)
                    {
                        return (false, "授权短信验证码不正确或已过期, 请重新发送!");
                    }

                    if (!string.IsNullOrWhiteSpace(captcha.ErrorMessage))
                    {
                        return (false, captcha.ErrorMessage);
                    }
                }

                // 登录成功
                userContext = await _authorizationService.GetUserContextAsync(user.UserName);
                if (userContext is not null)
                {
                    var claims = await userContext.User.GetUserClaimsAsync(_context, _appSetting.DataIsolate);
                    loginModel.ReturnUrl = HttpUtility.UrlDecode(_authenticationService.GetRedirectUrl(user, loginModel.ReturnUrl));
                    await _signInManager.SignInWithClaimsAsync(user, new AuthenticationProperties { IsPersistent = false, RedirectUri = loginModel.ReturnUrl }, claims);
                    _logger.LogDebug("user {user} login success for Captcha type", loginModel.UserName);
                    return (true, string.Empty);
                }

                errorMessage = AccountOptions.ErrorMessageSmsCaptchaError;
                break;
            default:
                break;
        }

        _logger.LogDebug("user {user} login failed, " + errorMessage, loginModel.UserName);
        return (false, errorMessage);
    }
    #endregion

    #region Weixin & bind phoneNumber
    /// <summary>
    /// 微信认证, 此方法提供微信小程序等非微信开放平台类似接入方式的微信认证过程
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [DisplayName("微信认证")]
    [HttpGet("api/Account/WeixinAuthorize")]
    [AccessAuthorize(Code = "AS0XAccountIWeixinAuthorize")]
    public async Task<IActionResult> WeixinAuthorizeAsync(string code)
    {
        await _weixinIdentityService.AuthorizeAsync(code);
        return Ok();
    }
    /// <summary>
    /// 微信登录, 微信认证的后续步骤
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [DisplayName("微信登录")]
    [HttpGet("api/Account/WeixinLogin")]
    [AccessAuthorize(Code = "AS0XAccountIWeixinLogin")]
    public async Task<IActionResult> WeixinLoginAsync() => Ok(await _weixinIdentityService.LoginAsync());

    [AllowAnonymous]
    [DisplayName("获取验证码")]
    [HttpGet("api/Account/GetCaptcha")]
    [AccessAuthorize(Code = "AS0XAccountIGetCaptcha")]
    public async Task<IActionResult> GetCaptchaAsync(string captchaId) => await _captchaService.GetCaptchaAsync(captchaId);

    [DisplayName("绑定手机号码")]
    [HttpGet("Account/BindPhoneNumber")]
    [AccessAuthorize(Code = "AS0XAccountPBindPhoneNumber", ResourceType = ResourceType.Page, AuthorizeType = AuthorizeType.Authenticator)]
    public IActionResult BindPhoneNumber()
    {
        var redirectUrl = Request.QueryString.ToString().Replace("?redirect_url=", "") ?? CHAR_SLASH.ToString();
        return View(new PhoneNumberConfirmedViewModel { ReturnUrl = redirectUrl });
    }

    [AllowAnonymous]
    [DisplayName("发送短信验证码")]
    [HttpPost("api/Account/SendCaptcha")]
    [AccessAuthorize(Code = "AS0XAccountISendCaptcha")]
    public async Task<IActionResult> SendCaptchaAsync(string phoneNumber)
    {
        //如果用户已登录, 则发送短信验证码为绑定手机号码的作用
        if (User.Identity?.IsAuthenticated ?? false && _userService.UserId is not null)
        {
            //先查询系统该手机号码是否已经被其他人绑定
            if (await _userService.AnyAsync(x => x.PhoneNumberConfirmed && x.PhoneNumber == phoneNumber && x.Id != _userService.UserId))
            {
                return BadRequest($"用户: {_userService.UserName} 已登录, 该手机号码属于其他人, 请检查手机号码是否正确!");
            }

            await _phoneNumberCaptchaService.SendCaptchaAsync(phoneNumber, false);
            return Ok(true);
        }

        //用户未登录的情况下发送短信验证为使用短信方式登录的作用, 此时, 要求用户已绑定手机号码
        var user = await _userService.FirstOrDefaultAsync(x => x.PhoneNumberConfirmed && x.PhoneNumber == phoneNumber);
        if (user is not null)
        {
            await _phoneNumberCaptchaService.SendCaptchaAsync(phoneNumber, true);
            var (needAuthorize, groups) = await NeedLoginAuthorizeAsync(user);
            if (needAuthorize)
            {
                var authorizeUser = await GetLoginAuthorizeUserAsync(user, groups);
                if (authorizeUser is not null && !string.IsNullOrWhiteSpace(authorizeUser.PhoneNumber) && _appSetting.SmsAuthorize is not null && user.UserName is not null && user.Name is not null)
                {
                    //发送短信验证码
                    var smsModel = _appSetting.SmsAuthorize.Copy();
                    smsModel.TemplateParam = new Dictionary<string, string> { { "name", user.Name } };
                    smsModel.Purpose = phoneNumber;
                    _logger.LogInformation($"当前用户: {user.Name} 需要验证码授权登录, 且已查询到授权人: {authorizeUser.UserName}, 将向授权人发送授权码!");
                    var captcha = await _phoneNumberCaptchaService.SendCaptchaAsync(authorizeUser.PhoneNumber, smsModel);

                    //发送系统消息
                    var message = $"当前用户: {user.Name}, 用户名: {user.UserName} 正在申请登录维修资金管理系统, 确认登录验证码: {captcha.Captcha}，该验证码 {_appSetting.Sms?.Expiration ?? 5} 分钟内有效，请勿泄漏于他人!";
                    await _communicator.SendAsync(message, authorizeUser.UserName, MessageType.SignIn);
                }
            }

            return Ok(true);
        }

        return BadRequest("手机号码不存在或尚未注册, 请先注册用户!");
    }
    /// <summary>
    /// 验证并绑定手机号码
    /// </summary>
    /// <param name="code">验证码</param>
    /// <returns></returns>
    [DisplayName("验证并绑定手机号码")]
    [HttpPost("Account/ConfirmPhoneNumber")]
    [AccessAuthorize(Code = "AS0XAccountPConfirmPhoneNumber", ResourceType = ResourceType.Page, AuthorizeType = AuthorizeType.Authenticator)]
    public async Task<IActionResult> ConfirmPhoneNumberAsync([FromForm] string code, [FromForm] string? returnUrl)
    {
        var viewModel = await _phoneNumberCaptchaService.ConfirmAsync(code, returnUrl);
        if (!string.IsNullOrWhiteSpace(viewModel.ErrorMessage))
        {
            viewModel.ReturnUrl = returnUrl;
            return View("BindPhoneNumber", viewModel);
        }

        return Redirect(HttpUtility.UrlDecode(viewModel.ReturnUrl!));
    }
    #endregion

    #region logout
    [AllowAnonymous]
    [DisplayName("注销")]
    [HttpGet("Account/Logout")]
    [AccessAuthorize(Code = "AS0XAccountPLogout", ResourceType = ResourceType.Page)]
    public async Task<IActionResult> LogoutAsync(string logoutId)
    {
        var userName = HttpContext.GetUserName();
        _logger.LogDebug("user {user} will to logout with logout id: " + logoutId, userName);

        await SignOutAsync();

        ArgumentNullException.ThrowIfNull(_appSetting.UserInteraction);
        var home = _appSetting.UserInteraction.Home;
        //logoutId ??= Request.GetRequestOption<string>(nameof(logoutId)) ?? await _interaction.CreateLogoutContextAsync();
        //if (!string.IsNullOrEmpty(logoutId))
        //{
        //    //var context = await _interaction.GetLogoutContextAsync(logoutId);
        //    //var client = await _clientStore.FindEnabledClientByIdAsync(context.ClientId ?? context.ClientIds.FirstOrDefault());
        //    //home = client?.ClientUri ?? home;
        //    //await HttpContext.SignOutAsync(new AuthenticationProperties { RedirectUri = context.SignOutIFrameUrl ?? _appSetting.UserInteraction.Home });
        //    //return RedirectToPage("/Account/LoggedOut", new LoggedOutViewModel
        //    //{
        //    //    LogoutId = logoutId,
        //    //    ClientName = context.ClientName,
        //    //    SignOutIframeUrl = context.SignOutIFrameUrl,
        //    //    PostLogoutRedirectUri = context.PostLogoutRedirectUri ?? _appSetting.UserInteraction.Home,
        //    //    AutomaticRedirectAfterSignOut = true
        //    //});

        //    _logger.LogDebug("user {user} logout success and redirect to: {clientUri}", userName, home);
        //}

        return Redirect(home);
    }
    [AllowAnonymous]
    [DisplayName("注销接口")]
    [HttpGet("api/Account/Logout")]
    [AccessAuthorize(Code = "AS0XAccountILogout")]
    public async Task<IActionResult> UserLogoutAsync()
    {
        _logger.LogDebug("user {user} will to logout", HttpContext.GetUserName());
        await SignOutAsync();

        var clientId = Request.GetRequestOption<string>(nameof(IdentitySetting.ClientId).ToCamelCase());
        if (clientId is not null)
        {
            //var client = await _clientStore.FindEnabledClientByIdAsync(clientId);
            //if (client is not null)
            //{
            //    return Redirect(client.ClientUri);
            //}
        }

        return Ok();
    }
    [AllowAnonymous]
    [DisplayName("已注销页面")]
    [HttpGet("Account/LoggedOut")]
    [AccessAuthorize(Code = "AS0XAccountPLoggedOut", ResourceType = ResourceType.Page)]
    public IActionResult LoggedOut()
    {
        return View();
    }
    /// <summary>
    /// 退出登录的核心逻辑
    /// </summary>
    /// <returns></returns>
    private async Task SignOutAsync()
    {
        await _signInManager.SignOutAsync();
        await HttpContext.SignOutAsync();
    }
    #endregion

    #region ResetPassword
    [DisplayName("重置用户密码")]
    [HttpGet("Account/ResetPassword")]
    [AccessAuthorize(Code = "AS0XAccountPResetPassword", ResourceType = ResourceType.Page)]
    public IActionResult ResetPassword(string? code = default)
    {
        return code == null ? View("Error") : View();
    }
    [DisplayName("确认重置用户密码")]
    [HttpGet("Account/ResetPasswordConfirm")]
    [AccessAuthorize(Code = "AS0XAccountPResetPasswordConfirm", ResourceType = ResourceType.Page)]
    public IActionResult ResetPasswordConfirm()
    {
        return View();
    }
    [ValidateAntiForgeryToken]
    [DisplayName("重置用户密码接口")]
    [HttpPost("Account/ResetPassword")]
    [AccessAuthorize(Code = "AS0XAccountIResetPassword", ResourceType = ResourceType.Page)]
    public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        if (string.IsNullOrWhiteSpace(model.UserName) || string.IsNullOrWhiteSpace(model.Password))
        {
            return BadRequest("用户名和密码不可为空!");
        }

        var user = await _userManager.FindByNameAsync(model.UserName);
        if (user is null || model.Token is null)
        {
            // Don't reveal that the user does not exist
            return RedirectToAction(nameof(ResetPasswordConfirm), "Account");
        }

        var code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(model.Token));
        var result = await _userManager.ResetPasswordAsync(user, code, model.Password);

        if (result.Succeeded)
        {
            return RedirectToAction(nameof(ResetPasswordConfirm), "Account");
        }

        return View();
    }
    /// <summary>
    /// 重置用户密码
    /// </summary>
    /// <returns></returns>

    [Display(Name = "重置用户的密码")]
    [HttpGet("api/Account/ResetPasswords/{userName}")]
    [Authorize(DEFAULT_AUTHORIZATION_POLICY, Roles = GROUP_MAINTAINERS)]
    [AccessAuthorize(Code = "AS0XAccountIResetPasswords")]
    public async Task<IActionResult> ResetPasswordsAsync(string userName)
    {
        var queryable = _userService.GetQueryable(x => x.Type != AuthorizeType.System && x.Type != AuthorizeType.Anonymous);
        if (string.IsNullOrWhiteSpace(userName))
        {
            return BadRequest("用户名不能为空!");
        }

        if (string.IsNullOrWhiteSpace(_appSetting.DefaultPassword))
        {
            return BadRequest("缺少默认密码配置!");
        }

        if (userName != "all")
        {
            queryable = queryable.Where(x => x.UserName == userName);
        }

        var users = await queryable.ToListAsync();
        if (users.Count == 0)
        {
            return BadRequest("用户不存在!");
        }

        foreach (var user in users)
        {
            var result = await _userManager.RemovePasswordAsync(user);
            if (result.Succeeded)
            {
                await _userManager.AddPasswordAsync(user, _appSetting.DefaultPassword);
            }
        }

        return Ok();
    }
    #endregion

    #region ForgotPassword
    [AllowAnonymous]
    [DisplayName("忘记密码")]
    [HttpGet("Account/ForgotPassword")]
    [AccessAuthorize(Code = "AS0XAccountPForgotPassword", ResourceType = ResourceType.Page)]
    public IActionResult ForgotPassword()
    {
        return View(new ForgotPasswordViewModel());
    }
    [AllowAnonymous]
    [DisplayName("忘记密码")]
    [HttpGet("Account/ForgotPasswordConfirm")]
    [AccessAuthorize(Code = "AS0XAccountPForgotPasswordConfirm", ResourceType = ResourceType.Page)]
    public IActionResult ForgotPasswordConfirm()
    {
        return View();
    }
    [ValidateAntiForgeryToken]
    [AllowAnonymous]
    [DisplayName("忘记密码")]
    [HttpPost("Account/ForgotPassword")]
    [AccessAuthorize(Code = "AS0XAccountIForgotPassword", ResourceType = ResourceType.Page)]
    public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
    {
        if (ModelState.IsValid && !string.IsNullOrWhiteSpace(model.UserName))
        {
            User? user;

            try
            {
                user = await _userManager.FindByNameAsync(model.UserName);
            }
            catch (Exception ex)
            {
                _logger.LogError($"Error retrieving user by userName ({model.UserName}) for forgot password functionality: {ex.Message}");
                user = null;
            }

            if (user is null || !await _userManager.IsEmailConfirmedAsync(user))
            {
                // Don't reveal that the user does not exist
                return View("ForgotPasswordConfirmation");
            }

            //var code = await _userManager.GeneratePasswordResetTokenAsync(user);
            //code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            //var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code }, HttpContext.Request.Scheme);

            //发送验证码到手机号码
            //await _emailSender.SendEmailAsync(user.Email, _localizer["ResetPasswordTitle"], _localizer["ResetPasswordBody", HtmlEncoder.Default.Encode(callbackUrl)]);

            return View("ForgotPasswordConfirmation");
        }

        return View(model);
    }
    #endregion

    #region other
    [AllowAnonymous]
    [DisplayName("拒绝访问")]
    [HttpGet("Account/AccessDenied")]
    [AccessAuthorize(Code = "AS0XAccountPAccessDenied", ResourceType = ResourceType.Page)]
    public IActionResult AccessDenied()
    {
        return View();
    }
    /// <summary>
    /// 个人信息
    /// </summary>
    /// <returns></returns>
    [DisplayName("个人信息")]
    [HttpGet("Account/Profile")]
    [Authorize(Roles = GROUP_AUTHENTICATOR)]
    [AccessAuthorize(Code = "AS0XAccountPProfile", ResourceType = ResourceType.Page, AuthorizeType = AuthorizeType.Authenticator)]
    public IActionResult Profile()
    {
        return View();
    }
    /// <summary>
    /// 获取个人信息
    /// </summary>
    /// <returns></returns>
    [Display(Name = "获取用户信息")]
    [HttpGet("api/Account/GetUserInfo")]
    [Authorize(Roles = GROUP_AUTHENTICATOR)]
    [AccessAuthorize(Code = "AS0XAccountIGetUserInfo", AuthorizeType = AuthorizeType.Authenticator)]
    public async Task<IActionResult> GetUserInfoAsync()
    {
        _logger.LogDebug("user {user} will get user info", HttpContext.GetUserName());
        var userInfo = await _authorizationService.GetUserInfoAsync();
        if (userInfo is null)
        {
            return NotFound();
        }

        return Ok(userInfo);
    }
    #endregion

    #region priviate methods
    /// <summary>
    /// 根据微信的 scheme 获取 oauth 请求的 state 参数
    /// </summary>
    /// <param name="returnUrl">处理完成后的返回链接地址</param>
    /// <returns></returns>
    private string? GetState(string returnUrl)
    {
        var id = KeyGenerator.GetStringKey();
        Response.Cookies.Append(CLAIM_TYPE_REDIRECT_URL, returnUrl);
        return _authenticationOptions.StateDataFormat?.Protect(new AuthenticationProperties
        {
            RedirectUri = _appSetting.UserInteraction!.Callback,
            Items =
            {
                //{ nameof(returnUrl), id },
                { "scheme", WeixinAuthenticationDefaults.AuthenticationScheme }
            }
        });
    }

    /// <summary>
    /// 是否需要登录验证, 如果用户登录需要二次验证, 则会向特定人群发送验证码
    /// </summary>
    /// <param name="user">登录用户</param>
    /// <returns></returns>
    private async Task<(bool, List<Group>?)> NeedLoginAuthorizeAsync(User user)
    {
        _logger.LogInformation($"查找用户: {user.UserName} 是否需要验证码授权登录!");

        var authorizeLogin = _appSetting.SmsAuthorizeLogin;
        if (authorizeLogin is not null && authorizeLogin.Enable)
        {
            //从用户名忽略名单判断
            if (!string.IsNullOrWhiteSpace(authorizeLogin.AuthorizeIgnoreUsers))
            {
                var ignores = authorizeLogin.AuthorizeIgnoreUsers.Split(CHAR_COMMA, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
                if (ignores.Length > 0 && ignores.Contains(user.UserName))
                {
                    _logger.LogInformation($"当前用户: {user.UserName} 不需要验证码授权登录!");
                    return (false, null);
                }
            }

            //从用户单位判断
            if (!string.IsNullOrWhiteSpace(authorizeLogin.AuthorizeGroups))
            {
                var authorizeGroups = authorizeLogin.AuthorizeGroups.Split(CHAR_COMMA, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
                var topGroups = await _context.Groups.Where(x => authorizeGroups.Contains(x.Id) || authorizeGroups.Contains(x.Name)).ToListAsync();
                if (topGroups is not null)
                {
                    var groups = new List<Group>();
                    foreach (var group in topGroups)
                    {
                        if (user.GroupId == group.Id)
                        {
                            groups.Add(group);
                        }
                        else
                        {
                            var childrenGroups = await _context.GetChildrenAsync<IdentityDbContext, Group>(group.Id, true);
                            if (user.GroupId is not null && childrenGroups.Any(x => x.Id == user.GroupId))
                            {
                                groups.Add(group);
                                groups.AddRange(childrenGroups);
                            }
                        }
                    }

                    if (groups.Count != 0)
                    {
                        _logger.LogInformation($"当前用户: {user.UserName} 需要验证码授权登录, 将向授权者发送短信验证码!");
                        return (true, groups);
                    }
                }
            }
        }

        _logger.LogInformation($"当前用户: {user.UserName} 不需要验证码授权登录!");
        return (false, null);
    }
    /// <summary>
    /// 登录验证, 如果用户登录需要二次验证, 则会向特定人群发送验证码
    /// </summary>
    /// <param name="user">登录用户</param>
    /// <returns></returns>
    private async Task<User?> GetLoginAuthorizeUserAsync(User user, List<Group>? groups)
    {
        //用户直属单位存在收费银行, 则登录需要二次验证
        var authorizeLogin = _appSetting.SmsAuthorizeLogin;
        if (authorizeLogin is not null && authorizeLogin.Enable && groups is not null && user.GroupId is not null && !string.IsNullOrWhiteSpace(authorizeLogin.AuthorizorRoles))
        {
            //此时需要二次验证
            List<string> GetUserGroups(string groupId)
            {
                var userGroupIds = new List<string>();
                var group = groups.FirstOrDefault(x => x.Id == groupId);
                if (group is not null)
                {
                    userGroupIds.Add(group.Id);
                    if (group.ParentId is not null)
                    {
                        userGroupIds.AddRange(GetUserGroups(group.ParentId));
                    }
                }

                return userGroupIds;
            }

            //过滤用户单位树
            var groupIds = GetUserGroups(user.GroupId);

            //查验证人
            var authorizorRoles = authorizeLogin.AuthorizorRoles.Split(CHAR_COMMA, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
            if (authorizorRoles.Length > 0)
            {
                foreach (var role in authorizorRoles)
                {
                    var authorizers = await _userStore.GetUsersInRoleAsync(role);
                    if (authorizers is not null && authorizers.Count > 0)
                    {
                        foreach (var groupId in groupIds)
                        {
                            var authorizer = authorizers.FirstOrDefault(x => x.GroupId != null && x.GroupId == groupId);
                            if (authorizer is not null && authorizer.PhoneNumber is not null && authorizer.PhoneNumberConfirmed && (authorizer.Id != user.Id || authorizer.Id == user.Id && authorizeLogin.AuthorizeOneself))
                            {
                                return authorizer;
                            }
                        }
                    }
                }
            }

            _logger.LogInformation($"当前用户: {user.UserName} 需要验证码授权登录, 但未查询到可用授权人!");
        }

        return null;
    }
    #endregion
}